package sweet.mvc.api

import scala.collection.{ mutable }
import sweet.helper.{ Logger, JMap, PropsContainer, InitDestroy }
import sweet.mvc.fm.{ ScalaFreemarkerConfiguration }
import sweet.mvc.core.{ ControllerContainer, LayoutContainer, FreemarkerViewRender , 
  SweetRequestProcessor, InPathDispatcherNameParser }
import sweet.mvc.api._

/** A container that hold all services and configs in a Sweet web application. 
 *
 * Subclass should override any default values and/or add more objects if needed.
 *
 */
trait SweetConfig extends ServletTypes
  with PropsContainer with ControllerContainer with LayoutContainer
  with InitDestroy with Logger {
    
  import Constants._
  
  // Default application Variables
  protected var _servletContext: javax.servlet.ServletContext = null // will be injected during dispatcher init
  def servletContext = _servletContext
  def setServletContext(ctx: javax.servlet.ServletContext){ _servletContext = ctx }
  
  // Default application Constants
  val defaultControllerName = "/main"
  val defaultHandlerName = "/index"
  val defaultLayoutName = "/view/layout/main.ftl"
  val viewNamePrefix = "/view"
  val viewNameSuffix = ".ftl"
  
  // View render implemenation using Freemarker template engine
  // NOTE that this must be lazy to guarantee servletContext has been set!
  lazy val viewRender = new FreemarkerViewRender(
    viewNamePrefix, viewNameSuffix, servletContext, new ScalaFreemarkerConfiguration)
  
  // Dispatcher implementation, again it must be lazy return.
  lazy val requestProcessor = new SweetRequestProcessor(
    new InPathDispatcherNameParser(defaultControllerName, defaultHandlerName),
    controllers, viewRender)
      
  /** Double check to ensure default settings are sensible. */
  override def init{
    super.init
        
    logger.debug("Sweet is initializing.")
        
    // === Global Properties Settings ===
    val ctxRealPath = servletContext.getRealPath("/")
    logger.debug("Exporting servletContext real path " + ctxRealPath)
    addProps(CONTEXT_REAL_PATH_KEY->ctxRealPath)
    
    // === View Render Settings ===
    if(viewRender.isInstanceOf[FreemarkerViewRender]){
      logger.debug("Auto injecting servletContext to freemarker config object.")
      val freemarkerConfig = viewRender.freemarkerConfig
      freemarkerConfig.setTemplateLoader(new freemarker.cache.WebappTemplateLoader(servletContext, "/"))
      
      // Auto import all layout as Macro into Freemarker's namespace!
      logger.debug("Add autoImports to all layouts into macro namespace " + layouts)
      freemarkerConfig.setAutoImports(JMap(layouts)) 
    }    
    
    // === Action Handlers, Controller, and View Settings ===
    
    // If user has no controller defined, add one.
    if(!_controllers.contains(defaultControllerName)){
      logger.debug("Auto injecting default HandlerNameViewController as " + defaultControllerName)
      _controllers(defaultControllerName) = new HandlerNameViewController
    }
    
    // Each controller must have a index handler
    for((ctlName, ctl) <- _controllers){
      if(!ctl.handlers.contains(defaultHandlerName)){
        logger.debug("Auto injecting default ViewHandler as "+ctlName+defaultHandlerName)
        ctl.handle(defaultHandlerName){ new View(defaultHandlerName) }
      }
    }
    
    // There should be a main layout as default.
    if(layouts.size == 0){
      logger.debug("Auto injecting default main layout " + defaultLayoutName)
      addLayouts("main"->defaultLayoutName)
    }
    
    // Create a map of controller and handler sitemap object and expose to application appCtxope
    logger.debug("Exporting action handler siteMap to ctx " + CONTROLLER_HANDLER_SITEMAP_KEY)
    val map = new mutable.HashMap[String, List[String]]
    for((k,v) <- controllers)
      map += Pair(k, v.handlers.keys.toList)
    servletContext.setAttribute(CONTROLLER_HANDLER_SITEMAP_KEY, map.readOnly)
    
    logger.info("Sweet init completed")
       
    
    // Display what we have initialized in this config container
    logger.info("="*40)
    
    logger.debug("Listing of config props:")
    for((k,v) <- props)
       logger.debug("  "+k+": "+v)
      
    logger.info("Listing of action handler mappings: ")
    for((kc,c) <- _controllers){
      logger.debug("  "+kc+": "+c.getClass)
      for((kh,h) <- c.handlers)
       logger.debug("    "+kh+": "+h.getClass)
    }
    
    logger.info("="*40)
  }
  
  /** Clean up any resources if there is any. */
  override def destroy{
    super.init
    
    logger.debug("Sweet is shutting down.")
    
    //No thing to clean up.
    
    logger.info("Sweet shutdown completed.")  
  }
}

